/**
 * 
 */
package com.sc.demo.plugins;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.log4j.Logger;

import com.sc.demo.annotation.AttributeColumnsMapper;
import com.sc.demo.router.SqlRewriter;
import com.sc.demo.util.ReflectUtils;


/**
 * @author huan
 *
 */
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class , Integer.class}) })
public class AttributeColumnsMapperPlugin implements Interceptor {
    
	private Logger logger = Logger.getLogger(AttributeColumnsMapperPlugin.class);
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		Connection connection = (Connection) invocation.getArgs()[0];
		logger.debug("[AttributeColumnsMapperPlugin] Target =" +  invocation.getTarget());
		logger.debug("[AttributeColumnsMapperPlugin] Catalog = " + connection.getCatalog());
		logger.debug("[AttributeColumnsMapperPlugin] Method=" + invocation.getMethod());
		Object statement =  invocation.getTarget();
		BaseStatementHandler handler = (BaseStatementHandler) ReflectUtils.getFieldValue(statement, "delegate");
		MappedStatement mapper=(MappedStatement)ReflectUtils.getFieldValue(handler, "mappedStatement");
		String mapperName=mapper.getId().substring(0, mapper.getId().lastIndexOf("."));
		Class<?> clazz=Class.forName(mapperName);
		AttributeColumnsMapper asm = (AttributeColumnsMapper) clazz.getAnnotation(AttributeColumnsMapper.class);
		if(asm != null ){ 
			BoundSql boundSql = handler.getBoundSql();
			String sql = (String) ReflectUtils.getFieldValue(boundSql, "sql");
			logger.debug("[AttributeColumnsMapperPlugin] initSQL=" + sql);
			logger.debug("[AttributeColumnsMapperPlugin] parameterMappings =" + handler.getBoundSql().getParameterMappings());
			logger.debug("[AttributeColumnsMapperPlugin] AttributeColumnsMapperAnnotation=" + asm);
			String newSQL = SqlRewriter.rewriteSqlTable(sql, asm.table(), asm.table());	
			logger.debug("[AttributeColumnsMapperPlugin] overSQL=" + newSQL);
			ReflectUtils.setFieldValue(boundSql, "sql",newSQL);
			ReflectUtils.setFieldValue(handler,"boundSql",boundSql);
		}
		try {
			return prepare(handler, connection);
		} catch (SQLException e) {
			return null;
		}
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}
	 
	private Statement prepare(BaseStatementHandler handler, Connection connection) throws SQLException {
		return handler.prepare(connection, null);
	}
	public void setProperties(Properties properties) {
	}
}
